/*
 * Copyright(C) 2009, kesalin All rights reserved.
 * 
 * File name : DropTargetImpl.h
 * Brief     : Implement of drop-target.
 * Version   : 1.0
 * Author    : kesalin@gmail.com
 * Date      : 2009-6-5
 */


#pragma once

// DropTargetImpl
class DropTargetImpl :
	public ATL::CComObjectRootEx<ATL::CComSingleThreadModel>,
	public DragDrop::IDropTargetImpl<DropTargetImpl> {

	void*                       m_Context;
	LuoDnDAssist::DropCallback_t m_Callback;

public:

	BEGIN_COM_MAP(DropTargetImpl)
		COM_INTERFACE_ENTRY(IDropTarget)
	END_COM_MAP()

public:

	DropTargetImpl() : m_Context(0), m_Callback(0)
	{
	}

	~DropTargetImpl()
	{
	}

	/* */

	HRESULT FinalConstruct()
	{
		return S_OK;
	}

	void FinalRelease()
	{
		if (m_Callback != 0) {
			m_Callback(m_Context, LuoDnDAssist::DT_FinalRelease, 0);
		}
	}

	/* */

	void Setup(
		void* ctx,
		LuoDnDAssist::DropCallback_t cb)
	{
		m_Context = ctx;
		m_Callback = cb;
	}

	/* */

	HRESULT OnDropEvent(
		int           type,
		IDataObject*  pDataObj,
		DWORD         grfKeyState,
		const POINTL* pt,
		DWORD*        pdwEffect)
	{
		HRESULT hRslt = S_OK;

		if (m_Callback != 0) {
			LuoDnDAssist::DropParam para = { 0 };

			para.pDataObj = pDataObj;

			para.grfKeyState = grfKeyState;
			if (pt != 0) {
				para.x = pt->x;
				para.y = pt->y;
			}

			para.dwEffectMask = DROPEFFECT_NONE;
			para.dwEffect     = DROPEFFECT_NONE;

			if (pdwEffect != 0) {
				para.dwEffectMask = *pdwEffect;
			}

			hRslt = m_Callback(
				m_Context,
				type,
				&para);

			if (pdwEffect != 0) {
				*pdwEffect = para.dwEffect;
			}
		}

		if (FAILED(hRslt)) {
			return hRslt;
		}

		return S_OK;
	}

	/* */

	static HRESULT Activate(
		void*                       context,
		LuoDnDAssist::DropCallback_t callback,
		IDropTarget**               pp)
	{
		if (pp == 0) {
			return E_INVALIDARG;
		}

		ATL::CComObject<DropTargetImpl>* impl = 0;
		HRESULT hRslt = ATL::CComObject<DropTargetImpl>::CreateInstance(&impl);
		if (FAILED(hRslt)) {
			return hRslt;
		}

		impl->AddRef();
		impl->Setup(context, callback);

		*pp = impl;

		return S_OK;
	}

	/* */

}; // DropTargetImpl

